#pragma once
#include <memory>
#include <semaphore.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/service.h>
#include <google/protobuf/message.h>
#include "tinyrpc/base/future.hpp"
namespace TinyRPC{
    
enum RPCRequestInfoStatus{
    SEND,                    // 发送出去
    SUCCESS,                  // 成功
    FAIL,                     // 失败
    TIMEOUT                  // 超时
};


class RPCRequestInfo{
    private:
        uint32_t m_no;
        sem_t m_sem;
        google::protobuf::Message* m_response;
        int m_tryTimes;                     // 尝试次数
        RPCRequestInfoStatus m_status;

        
    public:
        RPCRequestInfo(google::protobuf::Message* response){
            m_status = SEND;
            sem_init(&m_sem, 0, 0);
            m_response = response;
            m_tryTimes = 0;
        }
        bool isSuccess(){
            if(m_status == RPCRequestInfoStatus::SEND){
                sem_wait(&m_sem);
            }
            return m_status == SUCCESS;
        }

        template<typename T>
        T* getResponse(){
            if(m_status == RPCRequestInfoStatus::SEND){
                sem_wait(&m_sem);
            }
            return (T*)m_response;
        }

        void setSuccAndParse(std::string response_str){
            m_response->ParseFromString(response_str);
            m_status = SUCCESS;
            sem_post(&m_sem);
        }

        void setFail(){
            m_status = FAIL;
            sem_post(&m_sem);
        }

        void setTimeOut(){
            m_status = TIMEOUT;
            sem_post(&m_sem);
        }

        void setStatus(RPCRequestInfoStatus status){
            m_status = status;
        }
        
        RPCRequestInfoStatus getStatus(){
            return m_status ;
        }

        void increaseTryTime(){
            m_tryTimes ++;
        }

        int getTryTimes(){
            return m_tryTimes;
        }

        void setNo(uint32_t no){
            m_no = no;
        }
        uint32_t getNo(){
            return m_no;
        }


};

using RPCRequestInfoPtr = std::shared_ptr<RPCRequestInfo>;
}